#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <filesystem>
#include <cctype>
#include <algorithm>

#include "conver"
#include "conver.h"

namespace fs = std::filesystem;

/**
 * @brief 判断一行是否只包含空格和/或制表符
 * @param line 待检查的字符串
 * @return 如果全是空白字符返回 true，否则返回 false
 */
bool isWhitespaceOnly(const std::string& line) {
    for (char c : line) {
        if (c != ' ' && c != '\t') {
            return false;
        }
    }
    return true;
}

/**
 * @brief 判断一行是否是 Allman 风格的左大括号行
 *        即该行只包含空格、制表符和一个单独的左大括号 '{'
 * @param line 待检查的字符串
 * @return 如果是 Allman 左大括号行返回 true，否则返回 false
 */
bool isAllmanLeftBraceLine(const std::string& line) {
    std::string trimmed;
    // 提取非空白字符
    for (char c : line) {
        if (c != ' ' && c != '\t') {
            trimmed += c;
        }
    }
    // 检查非空白字符是否正好是 "{"
    return trimmed == "{";
}

/**
 * @brief 将 Allman 风格的代码转换为 K&R 风格
 * @param inputLines 输入的代码行向量
 * @return 转换后的代码行向量
 */
std::vector<std::string> convertAllmanToKnr(const std::vector<std::string>& inputLines) {
    std::vector<std::string> outputLines;
    bool pendingBrace = false; // 标记上一行是否需要追加左大括号

    for (const std::string& line : inputLines) {
        // 如果当前行是 Allman 风格的左大括号行
        if (isAllmanLeftBraceLine(line)) {
            pendingBrace = true; // 标记需要将 '{' 追加到上一行
            // 不将此行添加到输出，因为它将被合并
            continue;
        }

        // 如果有等待追加的左大括号，且当前行不是空白行
        if (pendingBrace && !isWhitespaceOnly(line)) {
            // 获取上一行（outputLines 的最后一行）
            if (!outputLines.empty()) {
                std::string& lastLine = outputLines.back();
                // 移除上一行末尾的空格（为了美观）
                while (!lastLine.empty() && (lastLine.back() == ' ' || lastLine.back() == '\t')) {
                    lastLine.pop_back();
                }
                // 追加空格和左大括号
                lastLine += " {";
            }
            pendingBrace = false; // 重置标记
        }

        // 将当前行添加到输出
        outputLines.push_back(line);
    }

    // 处理文件末尾的特殊情况：如果文件以 Allman 左大括号结尾且后面没有内容
    // 这种情况在实际代码中很少见，但为了健壮性
    if (pendingBrace) {
        if (!outputLines.empty()) {
            std::string& lastLine = outputLines.back();
            while (!lastLine.empty() && (lastLine.back() == ' ' || lastLine.back() == '\t')) {
                lastLine.pop_back();
            }
            lastLine += " {";
        }
    }

    return outputLines;
}

/**
 * @brief 读取文件的所有行到向量中
 * @param filename 文件名
 * @param lines 用于存储行的向量
 * @return 成功读取返回 true，否则返回 false
 */
bool readFileLines(const std::string& filename, std::vector<std::string>& lines) {
    std::ifstream file(filename);
    if (!file.is_open()) {
        std::cerr << "错误: 无法打开文件 '" << filename << "' 进行读取。\n";
        return false;
    }

    lines.clear();
    std::string line;
    while (std::getline(file, line)) {
        lines.push_back(line);
    }
    file.close();
    return true;
}

/**
 * @brief 将向量中的行写入文件
 * @param filename 文件名
 * @param lines 要写入的行向量
 * @return 成功写入返回 true，否则返回 false
 */
bool writeFileLines(const std::string& filename, const std::vector<std::string>& lines) {
    std::ofstream file(filename);
    if (!file.is_open()) {
        std::cerr << "错误: 无法打开文件 '" << filename << "' 进行写入。\n";
        return false;
    }

    for (size_t i = 0; i < lines.size(); ++i) {
        file << lines[i];
        if (i < lines.size() - 1) {
            file << '\n'; // 避免在文件末尾添加额外的换行符
        }
    }
    file.close();
    return true;
}

/**
 * @brief 检查文件扩展名是否为 .c 或 .cpp
 * @param filename 文件名
 * @return 如果是 .c 或 .cpp 返回 true，否则返回 false
 */
bool isCppOrCFile(const std::string& filename) {
    if (filename.length() < 3) return false;
    std::string ext = filename.substr(filename.length() - 4); // .cpp 或 .cxx 等
    std::string ext3 = filename.substr(filename.length() - 3); // .cc 或 .cp
    std::string ext2 = filename.substr(filename.length() - 2); // .c

    // 转换为小写进行比较
    std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
    std::transform(ext3.begin(), ext3.end(), ext3.begin(), ::tolower);
    std::transform(ext2.begin(), ext2.end(), ext2.begin(), ::tolower);

    return (ext == ".cpp" || ext == ".cxx" || ext == ".cc" || ext == ".cp" ||
            ext3 == ".cc" || ext3 == ".cp" ||
            ext2 == ".c");
}

/**
 * @brief 处理单个文件的转换
 * @param filename 文件名
 * @return 转换成功返回 true，否则返回 false
 */
bool processFile(const std::string& filename,bool mode_replace = true) {
    std::cout << "正在处理文件: " << filename << "\n";

    // 读取文件
    std::vector<std::string> lines;
    if (!readFileLines(filename, lines)) {
        return false;
    }

    // 转换风格
    std::vector<std::string> convertedLines = convertAllmanToKnr(lines);

    // 写回文件（这里选择覆盖原文件，也可以选择写入新文件）
    // 使用临时文件以确保原子性
    std::string tempFilename = filename + ".tmp";
    if (!writeFileLines(tempFilename, convertedLines)) {
        std::remove(tempFilename.c_str()); // 清理临时文件
        return false;
    }

    // 替换原文件
    if(!mode_replace){
        std::rename(tempFilename.c_str(), (filename + ".kr").c_str());
    } else {
        if (std::rename(tempFilename.c_str(), filename.c_str()) != 0) {
            std::cerr << "错误: 无法重命名临时文件。\n";
            std::remove(tempFilename.c_str()); // 尝试清理
            return false;
        }
    }
    std::cout << "已成功转换为 K&R 风格: " << filename << "\n";
    return true;
}

/**
 * @brief 主函数
 * @param argc 参数个数
 * @param argv 参数数组
 * @return 程序退出状态
 */
int main(int argc, char* argv[]) {
    if (argc < 2) {
        std::cout << "用法: " << argv[0] << " <文件名1> [文件名2 ...]\n";
        std::cout << "       " << argv[0] << " <目录名>\n";
        return 1;
    }

    std::vector<std::string> filesToProcess;

    // 处理命令行参数
    for (int i = 1; i < argc; ++i) {
        const std::string arg = argv[i];

        if (fs::is_regular_file(arg)) {
            // 是文件
            if (isCppOrCFile(arg)) {
                filesToProcess.push_back(arg);
            } else {
                std::cerr << "警告: '" << arg << "' 不是 .c 或 .cpp 文件，已跳过。\n";
            }
        } else if (fs::is_directory(arg)) {
            // 是目录，遍历目录下的 .c 和 .cpp 文件
            try {
                for (const auto& entry : fs::directory_iterator(arg)) {
                    if (entry.is_regular_file() && isCppOrCFile(entry.path().string())) {
                        filesToProcess.push_back(entry.path().string());
                    }
                }
            } catch (const fs::filesystem_error& ex) {
                std::cerr << "错误: 无法遍历目录 '" << arg << "': " << ex.what() << "\n";
                continue;
            }
        } else {
            std::cerr << "错误: '" << arg << "' 既不是文件也不是目录。\n";
        }
    }

    if (filesToProcess.empty()) {
        std::cerr << "没有找到需要处理的 .c 或 .cpp 文件。\n";
        return 1;
    }

    int successCount = 0;
    int failureCount = 0;

    // 处理每个文件
    for (const std::string& filename : filesToProcess) {
        if (processFile(filename)) {
            successCount++;
        } else {
            failureCount++;
        }
    }

    std::cout << "\n转换完成。\n";
    std::cout << "成功: " << successCount << " 个文件\n";
    std::cout << "失败: " << failureCount << " 个文件\n";

    return (failureCount > 0) ? 1 : 0;
}